package com.ssy.lingxi.purchase.serviceimpl.needplan;

import cn.hutool.core.collection.CollectionUtil;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.feign.UploadControllerFeign;
import com.ssy.lingxi.purchase.api.dto.request.*;
import com.ssy.lingxi.purchase.api.dto.response.*;
import com.ssy.lingxi.purchase.api.enums.common.CommonBooleanEnum;
import com.ssy.lingxi.purchase.api.enums.needplan.NeedPlanInnerOperationStatusEnum;
import com.ssy.lingxi.purchase.api.enums.needplan.NeedPlanInnerRecordStatusEnum;
import com.ssy.lingxi.purchase.api.enums.needplan.NeedPlanInnerStatusEnum;
import com.ssy.lingxi.purchase.api.enums.purchase.StatusEnum;
import com.ssy.lingxi.purchase.entity.PurchaseNeedPlanDetail;
import com.ssy.lingxi.purchase.entity.needplan.NeedPlan;
import com.ssy.lingxi.purchase.entity.needplan.NeedPlanDetail;
import com.ssy.lingxi.purchase.entity.needplan.NeedPlanInnerRecord;
import com.ssy.lingxi.purchase.entity.needplan.QNeedPlan;
import com.ssy.lingxi.purchase.entity.purchaseplan.PurchasePlan;
import com.ssy.lingxi.purchase.entity.purchaseplan.PurchasePlanDetail;
import com.ssy.lingxi.purchase.repository.needplan.NeedPlanDetailRepository;
import com.ssy.lingxi.purchase.repository.needplan.NeedPlanRecordRepository;
import com.ssy.lingxi.purchase.repository.needplan.NeedPlanRepository;
import com.ssy.lingxi.purchase.repository.purchaseplan.PurchasePlanDetailRepository;
import com.ssy.lingxi.purchase.repository.purchaseplan.PurchasePlanRepository;
import com.ssy.lingxi.purchase.service.needplan.NeedPlanService;
import com.ssy.lingxi.purchase.utils.DateUtil;
import com.ssy.lingxi.purchase.utils.ExcelImportUtil;
import com.ssy.lingxi.report.api.enums.OperateDataSourceEnum;
import com.ssy.lingxi.report.api.enums.PurchaseNeedPlanOperateTypeEnum;
import com.ssy.lingxi.report.api.enums.PurchasePlanOperateTypeEnum;
import com.ssy.lingxi.report.api.feign.ReportControllerFeign;
import com.ssy.lingxi.report.api.vo.request.OperateNoticeVO;
import com.ssy.lingxi.workflow.api.feign.ProcessFeign;
import com.ssy.lingxi.workflow.api.model.contant.ProcessEnum;
import com.ssy.lingxi.workflow.api.model.contant.ProcessTaskStatusEnum;
import com.ssy.lingxi.workflow.api.model.vo.request.InternalProcessQueryVO;
import com.ssy.lingxi.workflow.api.model.vo.request.TaskExecuteVO;
import com.ssy.lingxi.workflow.api.model.vo.request.TaskStartVO;
import com.ssy.lingxi.workflow.api.model.vo.response.SimpleProcessDefVO;
import com.ssy.lingxi.workflow.api.model.vo.response.SimpleTaskCompleteVO;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 采购能力 - 需求计划管理 - 业务实现类
 * @author fhj
 * @date 2021/02/26
 * @version 2.0.0
 * */
@Slf4j
@Service
public class NeedPlanServiceImpl implements NeedPlanService {

    @Resource
    private UploadControllerFeign uploadControllerFeign;
    @Resource
    private ProcessFeign processFeign;
    @Resource
    private JdbcTemplate jdbcTemplate;
    @Resource
    private NeedPlanRepository needPlanRepository;
    @Resource
    private NeedPlanDetailRepository needPlanDetailRepository;
    @Resource
    private NeedPlanRecordRepository needPlanRecordRepository;
    @Resource
    private PurchasePlanRepository purchasePlanRepository;
    @Resource
    private PurchasePlanDetailRepository purchasePlanDetailRepository;
    @Resource
    private ReportControllerFeign reportControllerFeign;
    @Resource
    private JPAQueryFactory jpaQueryFactory;

    @Override
    @ApiOperation(value = "内部状态")
    public Wrapper<List<Map<String, Object>>> inner() {
        return Wrapper.success(NeedPlanInnerStatusEnum.getAll());
    }

    @Override
    @ApiOperation(value = "列表（所有）")
    public Wrapper<PageData<NeedPlanListResponse>> allList(NeedPlanListRequest qo, UserLoginCacheDTO user) {
        return Wrapper.success(commonList(qo, user));
    }

    @Override
    @ApiOperation(value = "列表（待新增）")
    public Wrapper<PageData<NeedPlanListResponse>> toBeAddList(NeedPlanListRequest qo, UserLoginCacheDTO user) {
        //获取内部状态为待提交审核、审核不通过（一级）、审核不通过（二级）、采购退回的需求计划
        qo.setInnerStatusList(Stream.of(
                NeedPlanInnerStatusEnum.TO_BE_SUBMIT_EXAM.getCode(),
                NeedPlanInnerStatusEnum.NOT_PASSED1.getCode(),
                NeedPlanInnerStatusEnum.NOT_PASSED2.getCode(),
                NeedPlanInnerStatusEnum.PURCHASE_RETURN.getCode()
        ).collect(Collectors.toList()));
        return Wrapper.success(commonList(qo, user));
    }

    @Override
    @ApiOperation(value = "列表（待一级审核）")
    public Wrapper<PageData<NeedPlanListResponse>> toBeFirstExamList(NeedPlanListRequest qo, UserLoginCacheDTO user) {
        //获取内部状态为待审核（一级）的需求计划
        qo.setInnerStatusList(Stream.of(
                NeedPlanInnerStatusEnum.TO_BE_EXAM1.getCode()
        ).collect(Collectors.toList()));
        return Wrapper.success(commonList(qo, user));
    }

    @Override
    @ApiOperation(value = "列表（待二级审核）")
    public Wrapper<PageData<NeedPlanListResponse>> toBeSecondExamList(NeedPlanListRequest qo, UserLoginCacheDTO user) {
        //获取内部状态为待审核（二级）的需求计划
        qo.setInnerStatusList(Stream.of(
                NeedPlanInnerStatusEnum.TO_BE_EXAM2.getCode()
        ).collect(Collectors.toList()));
        return Wrapper.success(commonList(qo, user));
    }

    @Override
    @ApiOperation(value = "列表（待提交采购汇总）")
    public Wrapper<PageData<NeedPlanListResponse>> toBeSubmitList(NeedPlanListRequest qo, UserLoginCacheDTO user) {
        //获取内部状态为待提交采购汇总的需求计划
        qo.setInnerStatusList(Stream.of(
                NeedPlanInnerStatusEnum.TO_BE_SUBMIT.getCode()
        ).collect(Collectors.toList()));
        return Wrapper.success(commonList(qo, user));
    }

    @Override
    @ApiOperation(value = "列表（待采购汇总）")
    public Wrapper<PageData<NeedPlanListResponse>> toBeCollectList(NeedPlanListRequest qo, UserLoginCacheDTO user) {
        //获取内部状态为待采购汇总的需求计划
        qo.setInnerStatusList(Stream.of(
                NeedPlanInnerStatusEnum.TO_BE_COLLECT.getCode()
        ).collect(Collectors.toList()));
        return Wrapper.success(commonList(qo, user));
    }

    @Override
    @ApiOperation(value = "详情")
    public Wrapper<NeedPlanResponse> details(CommonIdRequest dto, UserLoginCacheDTO user) {
        //根据ID获取需求计划详情
        NeedPlan needPlan = needPlanRepository.findById(dto.getId()).orElse(null);
        if(needPlan == null) {
            return Wrapper.fail(ResponseCode.PURCHASE_NO_DEMAND_PLANNING_INFORMATION_FOUND_BY_ID);
        }

        //拷贝
        NeedPlanResponse response = new NeedPlanResponse();
        BeanUtils.copyProperties(needPlan, response);

        //封装内部状态名称
        response.setInnerStatusName(NeedPlanInnerStatusEnum.getMessage(response.getInnerStatus()));

        //根据需求计划ID获取需求计划内部工作流记录集合
        List<NeedPlanInnerRecord> innerRecords = needPlanRecordRepository.findByNeedPlanId(dto.getId(), Sort.by("id").ascending());
        response.setInnerRecords(innerRecords.stream().map(a -> {
            NeedPlanInnerRecordResponse recordResponse = new NeedPlanInnerRecordResponse();
            BeanUtils.copyProperties(a, recordResponse);
            //国际化处理
            recordResponse.setStatus(NeedPlanInnerRecordStatusEnum.getMessage(a.getStatus()));
            recordResponse.setOperate(NeedPlanInnerOperationStatusEnum.getMessage(a.getOperate()));
            recordResponse.setOpinion(StatusEnum.AGREE.getCHName().equals(a.getOpinion())? StatusEnum.getName(a.getOpinion()) : a.getOpinion());
            return recordResponse;
        }).collect(Collectors.toList()));

        //根据需求计划ID获取需求计划明细
        List<NeedPlanDetail> details = needPlanDetailRepository.findByNeedPlanId(dto.getId());
        response.setDetails(details.stream().map(a -> {
            NeedPlanDetailsResponse needPlanDetailsResponse = new NeedPlanDetailsResponse();
            BeanUtils.copyProperties(a, needPlanDetailsResponse);
            return needPlanDetailsResponse;
        }).collect(Collectors.toList()));

        //获取需求计划内部工作流程, 调用工作流服务 -> 查询单一的内部流程的定义
        InternalProcessQueryVO internalProcessQueryVO = new InternalProcessQueryVO();
        internalProcessQueryVO.setProcessKey(response.getInnerProcessKey());
        internalProcessQueryVO.setTaskId(response.getInnerTaskId());
        internalProcessQueryVO.setMemberId(response.getMemberId());
        Wrapper<SimpleProcessDefVO> wrapper = processFeign.findSimpleInternalTaskDefinitions(internalProcessQueryVO);
        if(wrapper.getCode() != ResponseCode.SUCCESS.getCode()) {
            log.error("工作流服务异常:" + wrapper.getMessage());
            throw new BusinessException(ResponseCode.ENHANCE_WORKFLOW_ERROR);
        }
        //封装需求计划内部工作流程
        List<TaskStepResponse> innerTaskList = wrapper.getData().getTasks().stream().map(a -> {
            TaskStepResponse taskStepVO = new TaskStepResponse();
            taskStepVO.setStep(a.getTaskStep());
            taskStepVO.setRoleName(a.getRoleName());
            taskStepVO.setTaskName(a.getTaskName());
            if(wrapper.getData().getCurrentStep() == 0 || wrapper.getData().getCurrentStep() >= a.getTaskStep()) {
                taskStepVO.setIsExecute(CommonBooleanEnum.YES.getCode());
            }else {
                taskStepVO.setIsExecute(CommonBooleanEnum.NO.getCode());
            }
            return taskStepVO;
        }).collect(Collectors.toList());
        response.setInnerTaskList(innerTaskList);

        return Wrapper.success(response);
    }

    @Override
    @ApiOperation(value = "需求计划明细")
    public Wrapper<PageData<NeedPlanDetail>> needPlanDetail(CommonIdPageRequest dto, UserLoginCacheDTO user) {
        Pageable pageable = PageRequest.of(dto.getCurrent() - 1, dto.getPageSize(), Sort.by("createTime").ascending());
        Page<NeedPlanDetail> page = needPlanDetailRepository.findByNeedPlanId(dto.getId(), pageable);
        return Wrapper.success(new PageData<>(page.getTotalElements(), page.getContent()));
    }

    @Override
    @Transactional
    @ApiOperation(value = "新增")
    public Wrapper<Void> add(AddNeedPlanRequest dto, UserLoginCacheDTO user) {
        //新增需求计划
        NeedPlan needPlan = new NeedPlan();
        needPlan.setMemberId(user.getMemberId());
        needPlan.setRoleId(user.getMemberRoleId());
        needPlan.setUserId(user.getUserId());
        needPlan.setStartTime(DateUtil.getStartDate(new Date(dto.getStartTime())));
        needPlan.setEndTime(DateUtil.getStartDate(new Date(dto.getEndTime())));
        needPlan.setSummary(dto.getSummary());
        needPlan.setDepartment(user.getUserOrgName());
        needPlan.setUserName(user.getUserName());
        needPlan.setAddType(dto.getAddType());
        needPlan.setInnerProcessKey(ProcessEnum.NEED_PLAN_INNER_VERIFY.getProcessKey());
        needPlanRepository.saveAndFlush(needPlan);

        //批量保存需求计划明细
        List<NeedPlanDetail> needPlanDetails = dto.getDetails().stream().map(a -> {
            NeedPlanDetail needPlanDetail = new NeedPlanDetail();
            BeanUtils.copyProperties(a, needPlanDetail);
            needPlanDetail.setNeedPlanId(needPlan.getId());
            return needPlanDetail;
        }).collect(Collectors.toList());
        needPlanDetailRepository.saveAll(needPlanDetails);

        //调用工作流服务 -> 开启内部工作流
        TaskStartVO taskStartVO = new TaskStartVO();
        taskStartVO.setProcessKey(needPlan.getInnerProcessKey());
        taskStartVO.setMemberId(needPlan.getMemberId());
        taskStartVO.setRoleId(needPlan.getRoleId());
        taskStartVO.setDataId(needPlan.getId());
        Wrapper<SimpleTaskCompleteVO> wrapper = processFeign.startSimpleProcess(taskStartVO);
        if(ResponseCode.SUCCESS.getCode() == wrapper.getCode()) {
            //更新内部状态、内部任务ID、需求计划编号
            needPlan.setInnerStatus(wrapper.getData().getStatus());
            needPlan.setInnerTaskId(wrapper.getData().getTaskId());
            needPlan.setNeedPlanNo("X" + Calendar.getInstance().get(Calendar.YEAR) + new DecimalFormat("00000").format(needPlan.getId()));
            needPlanRepository.saveAndFlush(needPlan);
        }else {
            log.error("工作流服务异常:" + wrapper.getMessage());
            throw new BusinessException(ResponseCode.SERVICE_WORKFLOW_ERROR);
        }

        //调用报表服务 -> 新增操作通知（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        addOperateNotice(
                user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.PURCHASE_NEED_PLAN.getCode(),
                PurchaseNeedPlanOperateTypeEnum.TO_BE_COMMIT_VALIFY_COUNT.getCode(),  1L,
                null, null
        );

        return Wrapper.success();
    }

    @Override
    @Transactional
    @ApiOperation(value = "修改")
    public Wrapper<Void> update(UpdateNeedPlanRequest dto, UserLoginCacheDTO user) {
        //根据ID获取需求计划详情
        NeedPlan needPlan = needPlanRepository.findById(dto.getId()).orElse(null);
        if(needPlan == null) {
            return Wrapper.fail(ResponseCode.PURCHASE_NO_DEMAND_PLANNING_INFORMATION_FOUND_BY_ID);
        }

        //获取修改需求计划之前的状态, 用于判断是否新增待办
        Integer status = needPlan.getInnerStatus();

        //修改需求计划
        needPlan.setCause(null);
        needPlan.setUserId(user.getUserId());
        needPlan.setStartTime(DateUtil.getStartDate(new Date(dto.getStartTime())));
        needPlan.setEndTime(DateUtil.getStartDate(new Date(dto.getEndTime())));
        needPlan.setSummary(dto.getSummary());
        needPlan.setDepartment(user.getUserOrgName());
        needPlan.setUserName(user.getUserName());
        needPlan.setAddType(dto.getAddType());

        //删除需求计划明细
        needPlanDetailRepository.deleteByNeedPlanId(dto.getId());

        //批量保存需求计划明细
        List<NeedPlanDetail> needPlanDetails = dto.getDetails().stream().map(a -> {
            NeedPlanDetail needPlanDetail = new NeedPlanDetail();
            BeanUtils.copyProperties(a, needPlanDetail);
            needPlanDetail.setNeedPlanId(needPlan.getId());
            return needPlanDetail;
        }).collect(Collectors.toList());
        needPlanDetailRepository.saveAll(needPlanDetails);

        //调用工作流服务 -> 开启内部工作流
        TaskStartVO taskStartVO = new TaskStartVO();
        taskStartVO.setProcessKey(needPlan.getInnerProcessKey());
        taskStartVO.setMemberId(needPlan.getMemberId());
        taskStartVO.setRoleId(needPlan.getRoleId());
        taskStartVO.setDataId(needPlan.getId());
        Wrapper<SimpleTaskCompleteVO> wrapper = processFeign.startSimpleProcess(taskStartVO);
        if(ResponseCode.SUCCESS.getCode() == wrapper.getCode()) {
            //更新内部状态、内部任务ID
            needPlan.setInnerStatus(wrapper.getData().getStatus());
            needPlan.setInnerTaskId(wrapper.getData().getTaskId());
            needPlanRepository.saveAndFlush(needPlan);
        }else {
            log.error("工作流服务异常:" + wrapper.getMessage());
            throw new BusinessException(ResponseCode.SERVICE_WORKFLOW_ERROR);
        }

        //如果状态是为待提交审核状态的话, 就不需要新增待办了。（避免待办数量统计错误）
        if(!status.equals(NeedPlanInnerStatusEnum.TO_BE_SUBMIT_EXAM.getCode())) {
            //调用报表服务 -> 新增操作通知（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
            addOperateNotice(
                    user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.PURCHASE_NEED_PLAN.getCode(),
                    PurchaseNeedPlanOperateTypeEnum.TO_BE_COMMIT_VALIFY_COUNT.getCode(),  1L,
                    null, null
            );
        }

        return Wrapper.success();
    }

    @Override
    @Transactional
    @ApiOperation(value = "删除")
    public Wrapper<Void> delete(CommonIdRequest dto, UserLoginCacheDTO user) {
        //根据ID获取需求计划详情
        NeedPlan needPlan = needPlanRepository.findById(dto.getId()).orElse(null);
        if(needPlan == null) {
            return Wrapper.fail(ResponseCode.PURCHASE_NO_DEMAND_PLANNING_INFORMATION_FOUND_BY_ID);
        }
        if(!needPlan.getInnerStatus().equals(NeedPlanInnerStatusEnum.TO_BE_SUBMIT_EXAM.getCode())) {
            return Wrapper.fail(ResponseCode.PURCHASE_ONLY_ALLOW_DELETION_OF_INTERNAL_STATES_THAT_ARE);
        }

        //删除需求计划、需求计划明细、内部工作流记录
        needPlanRepository.deleteById(dto.getId());
        needPlanDetailRepository.deleteByNeedPlanId(dto.getId());
        needPlanRecordRepository.deleteByNeedPlanId(dto.getId());

        //调用报表服务 -> 新增操作通知（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        addOperateNotice(
                user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.PURCHASE_NEED_PLAN.getCode(),
                null,  null,
                PurchaseNeedPlanOperateTypeEnum.TO_BE_COMMIT_VALIFY_COUNT.getCode(), 1L
        );

        return Wrapper.success();
    }

    @Override
    @Transactional
    @ApiOperation(value = "提交审核")
    public Wrapper<Void> submitExam(CommonIdRequest dto, UserLoginCacheDTO user) {
        //根据ID获取需求计划详情
        NeedPlan needPlan = needPlanRepository.findById(dto.getId()).orElse(null);
        if(needPlan == null) {
            return Wrapper.fail(ResponseCode.PURCHASE_NO_DEMAND_PLANNING_INFORMATION_FOUND_BY_ID);
        }

        //判断需求计划是否存在关联的内部记录, 如果有的话说明是修改过的需求计划
        Boolean flag = needPlanRecordRepository.existsByNeedPlanId(dto.getId());

        //调用工作流服务 -> 执行流程任务
        TaskExecuteVO taskExecuteVO = new TaskExecuteVO();
        taskExecuteVO.setMemberId(needPlan.getMemberId());
        taskExecuteVO.setRoleId(needPlan.getRoleId());
        taskExecuteVO.setDataId(needPlan.getId());
        taskExecuteVO.setTaskId(needPlan.getInnerTaskId());
        taskExecuteVO.setAgree(ProcessTaskStatusEnum.AGREE.getCode());
        taskExecuteVO.setProcessKey(needPlan.getInnerProcessKey());
        Wrapper<SimpleTaskCompleteVO> wrapper = processFeign.completeSimpleTask(taskExecuteVO);
        if(ResponseCode.SUCCESS.getCode() == wrapper.getCode()) {
            //记录需求计划内部工作流记录
            NeedPlanInnerRecord needPlanInnerRecord = new NeedPlanInnerRecord();
            needPlanInnerRecord.setNeedPlanId(needPlan.getId());
            needPlanInnerRecord.setUserId(user.getUserId());
            needPlanInnerRecord.setMemberId(user.getMemberId());
            needPlanInnerRecord.setRoleId(user.getMemberRoleId());
            needPlanInnerRecord.setStep(needPlan.getInnerStatus());
            needPlanInnerRecord.setOperator(user.getUserName());
            needPlanInnerRecord.setDepartment(user.getUserOrgName());
            needPlanInnerRecord.setJobTitle(user.getUserJobTitle());
            needPlanInnerRecord.setStatus(NeedPlanInnerRecordStatusEnum.TO_BE_EXAM1.getCHMessage());
            needPlanInnerRecord.setOperate(flag ? NeedPlanInnerOperationStatusEnum.UPDATE.getCHMessage() : NeedPlanInnerOperationStatusEnum.ADD.getCHMessage());
            needPlanInnerRecord.setOperateTime(System.currentTimeMillis());
            needPlanRecordRepository.saveAndFlush(needPlanInnerRecord);

            //更新内部状态、内部任务ID
            needPlan.setInnerStatus(wrapper.getData().getStatus());
            needPlan.setInnerTaskId(wrapper.getData().getTaskId());
            needPlanRepository.saveAndFlush(needPlan);
        }else {
            log.error("工作流服务异常:" + wrapper.getMessage());
            throw new BusinessException(ResponseCode.SERVICE_WORKFLOW_ERROR);
        }

        //调用报表服务 -> 新增操作通知（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        addOperateNotice(
                user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.PURCHASE_NEED_PLAN.getCode(),
                PurchaseNeedPlanOperateTypeEnum.TO_BE_VALIFY_STEP1_COUNT.getCode(),  1L,
                PurchaseNeedPlanOperateTypeEnum.TO_BE_COMMIT_VALIFY_COUNT.getCode(), 1L
        );

        return Wrapper.success();
    }

    @Override
    @Transactional
    @ApiOperation(value = "审核（一级）")
    public Wrapper<Void> firstExam(CommonExamRequest dto, UserLoginCacheDTO user) {
        //如果审核不通过时, 校验审核不通过原因是否为空
        if(dto.getStatus().equals(CommonBooleanEnum.NO.getCode()) && StringUtils.isBlank(dto.getCause())) {
            return Wrapper.fail("请输入审核不通过的原因");
        }

        //根据ID获取需求计划详情
        NeedPlan needPlan = needPlanRepository.findById(dto.getId()).orElse(null);
        if(needPlan == null) {
            return Wrapper.fail(ResponseCode.PURCHASE_NO_DEMAND_PLANNING_INFORMATION_FOUND_BY_ID);
        }

        //调用工作流服务 -> 执行流程任务
        TaskExecuteVO taskExecuteVO = new TaskExecuteVO();
        taskExecuteVO.setMemberId(needPlan.getMemberId());
        taskExecuteVO.setRoleId(needPlan.getRoleId());
        taskExecuteVO.setDataId(needPlan.getId());
        taskExecuteVO.setTaskId(needPlan.getInnerTaskId());
        taskExecuteVO.setAgree(dto.getStatus());
        taskExecuteVO.setProcessKey(needPlan.getInnerProcessKey());
        Wrapper<SimpleTaskCompleteVO> wrapper = processFeign.completeSimpleTask(taskExecuteVO);
        if(ResponseCode.SUCCESS.getCode() == wrapper.getCode()) {
            //记录需求计划内部工作流记录
            NeedPlanInnerRecord needPlanInnerRecord = new NeedPlanInnerRecord();
            needPlanInnerRecord.setNeedPlanId(needPlan.getId());
            needPlanInnerRecord.setUserId(user.getUserId());
            needPlanInnerRecord.setMemberId(user.getMemberId());
            needPlanInnerRecord.setRoleId(user.getMemberRoleId());
            needPlanInnerRecord.setStep(needPlan.getInnerStatus());
            needPlanInnerRecord.setOperator(user.getUserName());
            needPlanInnerRecord.setDepartment(user.getUserOrgName());
            needPlanInnerRecord.setJobTitle(user.getUserJobTitle());
            needPlanInnerRecord.setStatus(dto.getStatus().equals(CommonBooleanEnum.YES.getCode()) ? NeedPlanInnerRecordStatusEnum.TO_BE_EXAM2.getCHMessage() : NeedPlanInnerRecordStatusEnum.NOT_PASSED1.getCHMessage());
            needPlanInnerRecord.setOperate(NeedPlanInnerOperationStatusEnum.EXAM1.getCHMessage());
            needPlanInnerRecord.setOperateTime(System.currentTimeMillis());
            needPlanInnerRecord.setOpinion(dto.getStatus().equals(CommonBooleanEnum.YES.getCode()) ? StatusEnum.AGREE.getCHName() : dto.getCause());
            needPlanRecordRepository.saveAndFlush(needPlanInnerRecord);

            //更新内部状态、内部任务ID、原因
            needPlan.setInnerStatus(wrapper.getData().getStatus());
            needPlan.setInnerTaskId(wrapper.getData().getTaskId());
            needPlan.setCause(dto.getCause());
            needPlanRepository.saveAndFlush(needPlan);
        }else {
            log.error("工作流服务异常:" + wrapper.getMessage());
            throw new BusinessException(ResponseCode.SERVICE_WORKFLOW_ERROR);
        }

        //调用报表服务 -> 新增操作通知（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        if(dto.getStatus().equals(CommonBooleanEnum.YES.getCode())) {
            addOperateNotice(
                    user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.PURCHASE_NEED_PLAN.getCode(),
                    PurchaseNeedPlanOperateTypeEnum.TO_BE_VALIFY_STEP2_COUNT.getCode(),  1L,
                    PurchaseNeedPlanOperateTypeEnum.TO_BE_VALIFY_STEP1_COUNT.getCode(), 1L
            );
        }else {
            addOperateNotice(
                    user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.PURCHASE_NEED_PLAN.getCode(),
                   null,  null,
                    PurchaseNeedPlanOperateTypeEnum.TO_BE_VALIFY_STEP1_COUNT.getCode(), 1L
            );
        }



        return Wrapper.success();
    }

    @Override
    @Transactional
    @ApiOperation(value = "审核（二级）")
    public Wrapper<Void> secondExam(CommonExamRequest dto, UserLoginCacheDTO user) {
        //如果审核不通过时, 校验审核不通过原因是否为空
        if(dto.getStatus().equals(CommonBooleanEnum.NO.getCode()) && StringUtils.isBlank(dto.getCause())) {
            return Wrapper.fail("请输入审核不通过的原因");
        }

        //根据ID获取需求计划详情
        NeedPlan needPlan = needPlanRepository.findById(dto.getId()).orElse(null);
        if(needPlan == null) {
            return Wrapper.fail(ResponseCode.PURCHASE_NO_DEMAND_PLANNING_INFORMATION_FOUND_BY_ID);
        }

        //调用工作流服务 -> 执行流程任务
        TaskExecuteVO taskExecuteVO = new TaskExecuteVO();
        taskExecuteVO.setMemberId(needPlan.getMemberId());
        taskExecuteVO.setRoleId(needPlan.getRoleId());
        taskExecuteVO.setDataId(needPlan.getId());
        taskExecuteVO.setTaskId(needPlan.getInnerTaskId());
        taskExecuteVO.setAgree(dto.getStatus());
        taskExecuteVO.setProcessKey(needPlan.getInnerProcessKey());
        Wrapper<SimpleTaskCompleteVO> wrapper = processFeign.completeSimpleTask(taskExecuteVO);
        if(ResponseCode.SUCCESS.getCode() == wrapper.getCode()) {
            //记录需求计划内部工作流记录
            NeedPlanInnerRecord needPlanInnerRecord = new NeedPlanInnerRecord();
            needPlanInnerRecord.setNeedPlanId(needPlan.getId());
            needPlanInnerRecord.setUserId(user.getUserId());
            needPlanInnerRecord.setMemberId(user.getMemberId());
            needPlanInnerRecord.setRoleId(user.getMemberRoleId());
            needPlanInnerRecord.setStep(needPlan.getInnerStatus());
            needPlanInnerRecord.setOperator(user.getUserName());
            needPlanInnerRecord.setDepartment(user.getUserOrgName());
            needPlanInnerRecord.setJobTitle(user.getUserJobTitle());
            needPlanInnerRecord.setStatus(dto.getStatus().equals(CommonBooleanEnum.YES.getCode()) ? NeedPlanInnerRecordStatusEnum.TO_BE_SUBMIT.getCHMessage() : NeedPlanInnerRecordStatusEnum.NOT_PASSED2.getCHMessage());
            needPlanInnerRecord.setOperate(NeedPlanInnerOperationStatusEnum.EXAM2.getCHMessage());
            needPlanInnerRecord.setOperateTime(System.currentTimeMillis());
            needPlanInnerRecord.setOpinion(dto.getStatus().equals(CommonBooleanEnum.YES.getCode()) ? StatusEnum.AGREE.getCHName() : dto.getCause());
            needPlanRecordRepository.saveAndFlush(needPlanInnerRecord);

            //更新内部状态、内部任务ID、原因
            needPlan.setInnerStatus(wrapper.getData().getStatus());
            needPlan.setInnerTaskId(wrapper.getData().getTaskId());
            needPlan.setCause(dto.getCause());
            needPlanRepository.saveAndFlush(needPlan);
        }else {
            log.error("工作流服务异常:" + wrapper.getMessage());
            throw new BusinessException(ResponseCode.SERVICE_WORKFLOW_ERROR);
        }

        //调用报表服务 -> 新增操作通知（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        if(dto.getStatus().equals(CommonBooleanEnum.YES.getCode())) {
            addOperateNotice(
                    user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.PURCHASE_NEED_PLAN.getCode(),
                    PurchaseNeedPlanOperateTypeEnum.TO_BE_COMMIT_COUNT.getCode(),  1L,
                    PurchaseNeedPlanOperateTypeEnum.TO_BE_VALIFY_STEP2_COUNT.getCode(), 1L
            );
        }else {
            addOperateNotice(
                    user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.PURCHASE_NEED_PLAN.getCode(),
                    null,  null,
                    PurchaseNeedPlanOperateTypeEnum.TO_BE_VALIFY_STEP2_COUNT.getCode(), 1L
            );
        }

        return Wrapper.success();
    }

    @Override
    @Transactional
    @ApiOperation(value = "提交")
    public Wrapper<Void> submit(CommonIdRequest dto, UserLoginCacheDTO user) {
        //根据ID获取需求计划详情
        NeedPlan needPlan = needPlanRepository.findById(dto.getId()).orElse(null);
        if(needPlan == null) {
            return Wrapper.fail(ResponseCode.PURCHASE_NO_DEMAND_PLANNING_INFORMATION_FOUND_BY_ID);
        }

        //调用工作流服务 -> 执行流程任务
        TaskExecuteVO taskExecuteVO = new TaskExecuteVO();
        taskExecuteVO.setMemberId(needPlan.getMemberId());
        taskExecuteVO.setRoleId(needPlan.getRoleId());
        taskExecuteVO.setDataId(needPlan.getId());
        taskExecuteVO.setTaskId(needPlan.getInnerTaskId());
        taskExecuteVO.setAgree(ProcessTaskStatusEnum.GOTO_NEXT_STEP.getCode());
        taskExecuteVO.setProcessKey(needPlan.getInnerProcessKey());
        Wrapper<SimpleTaskCompleteVO> wrapper = processFeign.completeSimpleTask(taskExecuteVO);
        if(ResponseCode.SUCCESS.getCode() == wrapper.getCode()) {
            //记录需求计划内部工作流记录
            NeedPlanInnerRecord needPlanInnerRecord = new NeedPlanInnerRecord();
            needPlanInnerRecord.setNeedPlanId(needPlan.getId());
            needPlanInnerRecord.setUserId(user.getUserId());
            needPlanInnerRecord.setMemberId(user.getMemberId());
            needPlanInnerRecord.setRoleId(user.getMemberRoleId());
            needPlanInnerRecord.setStep(needPlan.getInnerStatus());
            needPlanInnerRecord.setOperator(user.getUserName());
            needPlanInnerRecord.setDepartment(user.getUserOrgName());
            needPlanInnerRecord.setJobTitle(user.getUserJobTitle());
            needPlanInnerRecord.setStatus(NeedPlanInnerRecordStatusEnum.TO_BE_COLLECT.getCHMessage());
            needPlanInnerRecord.setOperate(NeedPlanInnerOperationStatusEnum.SUBMIT.getCHMessage());
            needPlanInnerRecord.setOperateTime(System.currentTimeMillis());
            needPlanRecordRepository.saveAndFlush(needPlanInnerRecord);

            //更新内部状态、内部任务ID
            needPlan.setInnerStatus(wrapper.getData().getStatus());
            needPlan.setInnerTaskId(wrapper.getData().getTaskId());
            needPlanRepository.saveAndFlush(needPlan);
        }else {
            log.error("工作流服务异常:" + wrapper.getMessage());
            throw new BusinessException(ResponseCode.SERVICE_WORKFLOW_ERROR);
        }

        //调用报表服务 -> 新增操作通知（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        addOperateNotice(
                user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.PURCHASE_NEED_PLAN.getCode(),
                null,  null,
                PurchaseNeedPlanOperateTypeEnum.TO_BE_COMMIT_COUNT.getCode(), 1L
        );

        //调用报表服务 -> 新增操作通知（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        addOperateNotice(
                user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.PURCHASE_PLAN.getCode(),
                PurchasePlanOperateTypeEnum.TO_BE_SUMMARY_COUNT.getCode(),  1L,
                null, null
        );

        return Wrapper.success();
    }

    @Override
    @Transactional
    @ApiOperation(value = "退回")
    public Wrapper<Void> sendBack(CommonExamRequest dto, UserLoginCacheDTO user) {
        //根据ID获取需求计划详情
        NeedPlan needPlan = needPlanRepository.findById(dto.getId()).orElse(null);
        if(needPlan == null) {
            return Wrapper.fail(ResponseCode.PURCHASE_NO_DEMAND_PLANNING_INFORMATION_FOUND_BY_ID);
        }

        //调用工作流服务 -> 执行流程任务
        TaskExecuteVO taskExecuteVO = new TaskExecuteVO();
        taskExecuteVO.setMemberId(needPlan.getMemberId());
        taskExecuteVO.setRoleId(needPlan.getRoleId());
        taskExecuteVO.setDataId(needPlan.getId());
        taskExecuteVO.setTaskId(needPlan.getInnerTaskId());
        taskExecuteVO.setAgree(ProcessTaskStatusEnum.DISAGREE.getCode());
        taskExecuteVO.setProcessKey(needPlan.getInnerProcessKey());
        Wrapper<SimpleTaskCompleteVO> wrapper = processFeign.completeSimpleTask(taskExecuteVO);
        if(ResponseCode.SUCCESS.getCode() == wrapper.getCode()) {
            //记录需求计划内部工作流记录
            NeedPlanInnerRecord needPlanInnerRecord = new NeedPlanInnerRecord();
            needPlanInnerRecord.setNeedPlanId(needPlan.getId());
            needPlanInnerRecord.setUserId(user.getUserId());
            needPlanInnerRecord.setMemberId(user.getMemberId());
            needPlanInnerRecord.setRoleId(user.getMemberRoleId());
            needPlanInnerRecord.setStep(needPlan.getInnerStatus());
            needPlanInnerRecord.setOperator(user.getUserName());
            needPlanInnerRecord.setDepartment(user.getUserOrgName());
            needPlanInnerRecord.setJobTitle(user.getUserJobTitle());
            needPlanInnerRecord.setStatus(NeedPlanInnerRecordStatusEnum.PURCHASE_RETURN.getCHMessage());
            needPlanInnerRecord.setOperate(NeedPlanInnerOperationStatusEnum.RETURN.getCHMessage());
            needPlanInnerRecord.setOperateTime(System.currentTimeMillis());
            needPlanInnerRecord.setOpinion(dto.getCause());
            needPlanRecordRepository.saveAndFlush(needPlanInnerRecord);

            //更新内部状态、内部任务ID、退回原因
            needPlan.setInnerStatus(wrapper.getData().getStatus());
            needPlan.setInnerTaskId(wrapper.getData().getTaskId());
            needPlan.setCause(dto.getCause());
            needPlanRepository.saveAndFlush(needPlan);
        }else {
            log.error("工作流服务异常:" + wrapper.getMessage());
            throw new BusinessException(ResponseCode.SERVICE_WORKFLOW_ERROR);
        }

        //调用报表服务 -> 新增操作通知（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        addOperateNotice(
                user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.PURCHASE_PLAN.getCode(),
                null,  null,
                PurchasePlanOperateTypeEnum.TO_BE_SUMMARY_COUNT.getCode(), 1L
        );

        return Wrapper.success();
    }

    @Override
    @Transactional
    @ApiOperation(value = "汇总")
    public Wrapper<Void> collect(CommonIdListRequest dto, UserLoginCacheDTO user) {
        //根据ID集合获取需求计划集合
        List<NeedPlan> needPlanList = needPlanRepository.findAllById(dto.getIdList());
        if(CollectionUtil.isEmpty(needPlanList)) {
            return Wrapper.fail("根据ID未找到生产通知单信息");
        }

        //根据需求计划集合获取最小开始周期、最大结束周期、摘要
        long startTime = needPlanList.stream().mapToLong(NeedPlan::getStartTime).min().orElse(0L);
        long endTime = needPlanList.stream().mapToLong(NeedPlan::getEndTime).max().orElse(0L);
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        String summary = sf.format(new Date(startTime)) + "~" + sf.format(new Date(endTime)) + "采购计划";

        //新增采购计划
        PurchasePlan purchasePlan = new PurchasePlan();
        purchasePlan.setMemberId(user.getMemberId());
        purchasePlan.setRoleId(user.getMemberRoleId());
        purchasePlan.setUserId(user.getUserId());
        purchasePlan.setStartTime(startTime);
        purchasePlan.setEndTime(endTime);
        purchasePlan.setSummary(summary);
        purchasePlan.setDepartment(user.getUserOrgName());
        purchasePlan.setUserName(user.getUserName());
        purchasePlan.setInnerProcessKey(ProcessEnum.PURCHASE_PLAN_INNER_VERIFY.getProcessKey());
        purchasePlanRepository.saveAndFlush(purchasePlan);

        //获取需求计划集合内的所有明细
        List<NeedPlanDetail> needPlanDetailList = needPlanDetailRepository.findByNeedPlanIdIn(needPlanList.stream().map(NeedPlan::getId).collect(Collectors.toList()));

        //新增采购计划明细（首先将被汇总的所有需求采购明细按编号分组, 再根据每一组来拼装采购需求明细信息。）
        Map<String, List<NeedPlanDetail>> map = needPlanDetailList.stream().collect(Collectors.groupingBy(NeedPlanDetail::getNumber));
        List<PurchasePlanDetail> purchasePlanDetailList = new ArrayList<>();
        map.keySet().forEach(number -> {
            NeedPlanDetail needPlanDetail = map.get(number).stream().findFirst().orElse(new NeedPlanDetail());
            PurchasePlanDetail purchasePlanDetail = new PurchasePlanDetail();
            BeanUtils.copyProperties(needPlanDetail, purchasePlanDetail);
            purchasePlanDetail.setPurchasePlanId(purchasePlan.getId());
            purchasePlanDetail.setNumber(number);
            purchasePlanDetail.setName(needPlanDetail.getName());
            purchasePlanDetail.setModel(needPlanDetail.getModel());
            purchasePlanDetail.setCategory(needPlanDetail.getCategory());
            purchasePlanDetail.setBrand(needPlanDetail.getBrand());
            purchasePlanDetail.setUnit(needPlanDetail.getUnit());
            purchasePlanDetail.setCostPrice(needPlanDetail.getCostPrice());
            purchasePlanDetail.setPurchaseCount(map.get(number).stream().mapToDouble(NeedPlanDetail::getNeedCount).sum());
            purchasePlanDetail.setPurchasePrice(map.get(number).stream().mapToDouble(NeedPlanDetail::getCostPrice).sum());
            purchasePlanDetail.setPurchaseNeedPlanDetailList(
                    map.get(number).stream().map(a -> {
                        NeedPlan needPlan = needPlanList.stream().filter(b -> b.getId().equals(a.getNeedPlanId())).findFirst().orElse(new NeedPlan());
                        PurchaseNeedPlanDetail purchaseNeedPlanDetail = new PurchaseNeedPlanDetail();
                        purchaseNeedPlanDetail.setId(a.getId());
                        purchaseNeedPlanDetail.setNeedPlanNo(needPlan.getNeedPlanNo());
                        purchaseNeedPlanDetail.setStartTime(needPlan.getStartTime());
                        purchaseNeedPlanDetail.setEndTime(needPlan.getEndTime());
                        purchaseNeedPlanDetail.setSummary(needPlan.getSummary());
                        purchaseNeedPlanDetail.setDepartment(needPlan.getDepartment());
                        purchaseNeedPlanDetail.setUserName(needPlan.getUserName());
                        purchaseNeedPlanDetail.setCostPrice(a.getCostPrice());
                        purchaseNeedPlanDetail.setNeedPrice(a.getNeedPrice());
                        purchaseNeedPlanDetail.setNeedCount(a.getNeedCount());
                        purchaseNeedPlanDetail.setArriveTime(a.getArriveTime());
                        return purchaseNeedPlanDetail;
                    }).collect(Collectors.toList())
            );
            purchasePlanDetailList.add(purchasePlanDetail);
        });
        purchasePlanDetailRepository.saveAll(purchasePlanDetailList);

        //调用工作流服务 -> 开启内部工作流
        TaskStartVO taskStartVO = new TaskStartVO();
        taskStartVO.setProcessKey(purchasePlan.getInnerProcessKey());
        taskStartVO.setMemberId(purchasePlan.getMemberId());
        taskStartVO.setRoleId(purchasePlan.getRoleId());
        taskStartVO.setDataId(purchasePlan.getId());
        Wrapper<SimpleTaskCompleteVO> wrapper = processFeign.startSimpleProcess(taskStartVO);
        if(ResponseCode.SUCCESS.getCode() == wrapper.getCode()) {
            //更新内部状态、内部任务ID、采购计划编号
            purchasePlan.setInnerStatus(wrapper.getData().getStatus());
            purchasePlan.setInnerTaskId(wrapper.getData().getTaskId());
            purchasePlan.setPurchasePlanNo("C" + Calendar.getInstance().get(Calendar.YEAR) + new DecimalFormat("00000").format(purchasePlan.getId()));
            purchasePlanRepository.saveAndFlush(purchasePlan);
        }else {
            log.error("工作流服务异常:" + wrapper.getMessage());
            throw new BusinessException(ResponseCode.SERVICE_WORKFLOW_ERROR);
        }

        //遍历需求计划集合, 循环调用工作流服务, 调用成功时更新需求计划和新增内部工作流记录, 调用失败直接返回, 不需要抛出异常（调用成功得数据不需回滚）。
        for(NeedPlan needPlan:needPlanList) {
            //调用工作流服务 -> 执行流程任务
            TaskExecuteVO taskExecuteVO = new TaskExecuteVO();
            taskExecuteVO.setMemberId(needPlan.getMemberId());
            taskExecuteVO.setRoleId(needPlan.getRoleId());
            taskExecuteVO.setDataId(needPlan.getId());
            taskExecuteVO.setTaskId(needPlan.getInnerTaskId());
            taskExecuteVO.setAgree(ProcessTaskStatusEnum.AGREE.getCode());
            taskExecuteVO.setProcessKey(needPlan.getInnerProcessKey());
            wrapper = processFeign.completeSimpleTask(taskExecuteVO);
            if(ResponseCode.SUCCESS.getCode() == wrapper.getCode()) {
                //记录需求计划内部工作流记录
                NeedPlanInnerRecord needPlanInnerRecord = new NeedPlanInnerRecord();
                needPlanInnerRecord.setNeedPlanId(needPlan.getId());
                needPlanInnerRecord.setUserId(user.getUserId());
                needPlanInnerRecord.setMemberId(user.getMemberId());
                needPlanInnerRecord.setRoleId(user.getMemberRoleId());
                needPlanInnerRecord.setStep(needPlan.getInnerStatus());
                needPlanInnerRecord.setOperator(user.getUserName());
                needPlanInnerRecord.setDepartment(user.getUserOrgName());
                needPlanInnerRecord.setJobTitle(user.getUserJobTitle());
                needPlanInnerRecord.setStatus(NeedPlanInnerRecordStatusEnum.COLLECT_COMPLETE.getCHMessage());
                needPlanInnerRecord.setOperate(NeedPlanInnerOperationStatusEnum.COLLECT.getCHMessage());
                needPlanInnerRecord.setOperateTime(System.currentTimeMillis());
                needPlanRecordRepository.saveAndFlush(needPlanInnerRecord);

                //更新内部状态、内部任务ID
                needPlan.setInnerStatus(wrapper.getData().getStatus());
                needPlan.setInnerTaskId(wrapper.getData().getTaskId());
                needPlan.setPurchasePlanId(purchasePlan.getId());
                needPlanRepository.saveAndFlush(needPlan);
            }else {
                log.error("工作流服务异常:" + wrapper.getMessage());
                return Wrapper.fail("工作流服务异常，请稍后再试！");
            }

            //调用报表服务 -> 新增操作通知（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
            addOperateNotice(
                    user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.PURCHASE_PLAN.getCode(),
                    null,  null,
                    PurchasePlanOperateTypeEnum.TO_BE_SUMMARY_COUNT.getCode(), 1L
            );
        }

        //调用报表服务 -> 新增操作通知（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        addOperateNotice(
                user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.PURCHASE_PLAN.getCode(),
                PurchasePlanOperateTypeEnum.TO_BE_COMMIT_VALIFY_COUNT.getCode(),  1L,
                null, null
        );

        return Wrapper.success();
    }

    @Override
    @ApiOperation(value = "导入检查")
    public Wrapper<String> check(MultipartFile file) {
        List<NeedPlanExcelRequest> list;
        try {
            list = new ExcelImportUtil<NeedPlanExcelRequest>(NeedPlanExcelRequest.class).readExcel(file.getInputStream(), 1, 0);
        } catch (IOException e) {
            log.error("excel解析异常", e);
            return Wrapper.fail(ResponseCode.EXCEL_UPLOAD_ERROR);
        }
        if (CollectionUtils.isEmpty(list)) {
            return Wrapper.fail(ResponseCode.EXCEL_UPLOAD_ERROR_NULL);
        }
        String errorUrl = checkField(list);
        return Wrapper.success(errorUrl);
    }

    @Override
    @ApiOperation(value = "导入模板")
    public Wrapper<List<NeedPlanExcelRequest>> excel(MultipartFile file) {
        List<NeedPlanExcelRequest> list;
        try {
            list = new ExcelImportUtil<NeedPlanExcelRequest>(NeedPlanExcelRequest.class).readExcel(file.getInputStream(), 1, 0);
        } catch (IOException e) {
            log.error("excel解析异常", e);
            return Wrapper.fail(ResponseCode.EXCEL_UPLOAD_ERROR);
        }
        return Wrapper.success(list);
    }

    /**
     * 公共集合方法
     * */
    private PageData<NeedPlanListResponse> commonList(NeedPlanListRequest qo, UserLoginCacheDTO user) {
        QNeedPlan qNeedPlan = QNeedPlan.needPlan;
        JPAQuery<NeedPlanListResponse> jpaQuery = jpaQueryFactory
                .select(Projections.bean(NeedPlanListResponse.class,qNeedPlan.id,qNeedPlan.memberId,qNeedPlan.roleId,qNeedPlan.userId,qNeedPlan.needPlanNo,qNeedPlan.startTime,qNeedPlan.endTime,qNeedPlan.summary,qNeedPlan.department,qNeedPlan.userName,qNeedPlan.createTime,qNeedPlan.innerStatus))
                .from(qNeedPlan).where(qNeedPlan.memberId.eq(user.getMemberId()), qNeedPlan.roleId.eq(user.getMemberRoleId()));
        //拼接where条件
        if(CollectionUtil.isNotEmpty(qo.getInnerStatusList())) {
            jpaQuery.where(qNeedPlan.innerStatus.in(qo.getInnerStatusList()));
        }
        if(StringUtils.isNotBlank(qo.getNeedPlanNo())) {
            jpaQuery.where(qNeedPlan.needPlanNo.contains(qo.getNeedPlanNo()));
        }
        if(StringUtils.isNotBlank(qo.getSummary())) {
            jpaQuery.where(qNeedPlan.summary.contains(qo.getSummary()));
        }
        if(qo.getStartTime() != null) {
            jpaQuery.where(qNeedPlan.startTime.goe(qo.getStartTime()));
        }
        if(qo.getEndTime() != null) {
            jpaQuery.where(qNeedPlan.endTime.loe(qo.getEndTime()));
        }
        long totalCount = jpaQuery.fetchCount();
        List<NeedPlanListResponse> list = jpaQuery.orderBy(qNeedPlan.createTime.desc()).limit(qo.getPageSize()).offset((long) (qo.getCurrent() - 1) * qo.getPageSize()).fetch();
        //封装内部状态名称
        list.forEach(a -> a.setInnerStatusName(NeedPlanInnerStatusEnum.getMessage(a.getInnerStatus())));

        return new PageData<>(totalCount, list);
    }

    /**
     * excel字段校验
     * */
    private String checkField(List<NeedPlanExcelRequest> list) {
        int size = list.size();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < size; i++) {
            if (!org.springframework.util.StringUtils.hasLength(list.get(i).getNumber())) {
                sb.append("第").append(i).append("行物料编号为空\r\n");
            }
            if (!org.springframework.util.StringUtils.hasLength(list.get(i).getName())) {
                sb.append("第").append(i).append("行物料名称为空\r\n");
            }
            if (!org.springframework.util.StringUtils.hasLength(list.get(i).getModel())) {
                sb.append("第").append(i).append("行规格型号为空\r\n");
            }
            if (!org.springframework.util.StringUtils.hasLength(list.get(i).getCategory())) {
                sb.append("第").append(i).append("行品类为空\r\n");
            }
            if (!org.springframework.util.StringUtils.hasLength(list.get(i).getBrand())) {
                sb.append("第").append(i).append("行品牌为空\r\n");
            }
            if (!org.springframework.util.StringUtils.hasLength(list.get(i).getUnit())) {
                sb.append("第").append(i).append("行单位为空\r\n");
            }
            if (ObjectUtils.isEmpty(list.get(i).getCostPrice())) {
                sb.append("第").append(i).append("行成本价为空\r\n");
            }
            if (ObjectUtils.isEmpty(list.get(i).getNeedCount())) {
                sb.append("第").append(i).append("行需求数量为空\r\n");
            }
            if (ObjectUtils.isEmpty(list.get(i).getNeedPrice())) {
                sb.append("第").append(i).append("行需求金额为空\r\n");
            }
            if (ObjectUtils.isEmpty(list.get(i).getArriveTime())) {
                sb.append("第").append(i).append("行到货日期为空\r\n");
            }
        }
        Set<String> collect = list.stream().map(NeedPlanExcelRequest::getNumber).collect(Collectors.toSet());
        if (size != collect.size()) {
            sb.append("物料编号重复请检查数据");
        }
        if (org.springframework.util.StringUtils.hasLength(sb.toString())) {
            return writeErrorToTxt(sb.toString());
        }
        return null;
    }

    /**
     * 将错误信息输入到txt中
     * */
    public String writeErrorToTxt(String content) {
        File file = null;
        try {
            file = File.createTempFile("错误日记", ".txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
        getFile(content, file);
        MultipartFile multipartFile = getMulFileByFile(file);
        //上传到云服务器
        Wrapper<String> upload = uploadControllerFeign.upload(multipartFile);
        file.deleteOnExit();
        return upload.getData();
    }

    /**
     * 获取File文件
     * */
    public void getFile(String writeDate, File file) {
        BufferedWriter out = null;
        OutputStreamWriter osw = null;
        try {
            osw = new OutputStreamWriter(new FileOutputStream(file, true), StandardCharsets.UTF_8);
            out = new BufferedWriter(osw);
            osw.write(writeDate + "\r\n");
            osw.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (osw != null) {
                    osw.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取MultipartFile对象
     * */
    public static MultipartFile getMulFileByFile(File file) {
        FileItem fileItem = createFileItem(file.getPath(), file.getName());
        return new CommonsMultipartFile(fileItem);
    }

    /**
     * 创建FileItem对象
     * */
    public static FileItem createFileItem(String filePath, String fileName) {
        String fieldName = "file";
        FileItemFactory factory = new DiskFileItemFactory(16, null);
        FileItem item = factory.createItem(fieldName, "text/plain", false, fileName);
        File newfile = new File(filePath);
        int bytesRead;
        byte[] buffer = new byte[8192];
        try {
            FileInputStream fis = new FileInputStream(newfile);
            OutputStream os = item.getOutputStream();
            while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            fis.close();
        } catch (IOException e) {
            log.error("文件类型转换异常", e);
        }
        return item;
    }

    /**
     * 新增操作通知
     * @param memberId 会员ID
     * @param roleId 角色ID
     * @param dataSource 数据源
     * @param increaseStatus 增加的待办
     * @param increaseNum 增加的数量
     * @param reduceStatus 减少的待办
     * @param reduceNum 减少的数量
     */
    @Async
    public void addOperateNotice(Long memberId, Long roleId, Integer dataSource, Integer increaseStatus, Long increaseNum, Integer reduceStatus, Long reduceNum) {
        try {
            OperateNoticeVO noticeVO = new OperateNoticeVO();
            noticeVO.setMemberId(memberId);
            noticeVO.setRoleId(roleId);
            noticeVO.setDataSource(dataSource);

            //增加的待办与数量
            if(increaseStatus != null) {
                noticeVO.setIncreaseOperateType(increaseStatus);
                noticeVO.setIncreaseCount(increaseNum);
            }

            //减少的待办与数量
            if(reduceStatus != null) {
                noticeVO.setReduceOperateType(reduceStatus);
                noticeVO.setReduceCount(reduceNum);
            }

            reportControllerFeign.addOperateNotice(noticeVO);
        } catch (Exception e) {
            log.info("调用报表服务新增操作通知接口失败：{}", e.getMessage());
        }
    }
}
